#include <iostream>
#include <thread>
#include <brpc/channel.h>
#include "main.pb.h"

void callback(brpc::Controller* cntl, example::EchoResponse* rsp)
{
    //用智能指针管理，防止忘记释放造成的资源泄露
    std::unique_ptr<brpc::Controller> cntl_guard(cntl);
    std::unique_ptr<example::EchoResponse> rsp_guard(rsp);
    if(cntl->Failed() == true)
    {
        std::cout << "Rpc 调用失败！" << cntl->ErrorText() << std::endl;
        // delete cntl;
        // delete rsp;
        return;
    }
    std::cout << rsp->message() << std::endl;
    // delete cntl;
    // delete rsp;
}

int main(int argc, char* argv[])
{
    // 1.创建网络通信信道；
    brpc::ChannelOptions options;
    options.connect_timeout_ms = -1;    //连接等待超时时间，-1表示一直等待；
    options.timeout_ms = -1;    //rpc请求超时时间，-1表示一直有效
    options.protocol = "baidu_std"; //序列化协议，默认使用baidu_std
    options.max_retry = 3;  //请求重试次数
    brpc::Channel channel;
    int ret = channel.Init("127.0.0.1:8080", &options);
    if(ret == -1)
    {
        std::cout << "初始化信道失败！" << std::endl;
        return -1;
    }
    // 2.实例化pb中的EchoService_Stub类对象；
    example::EchoService_Stub stub(&channel);
    // 3.发起rpc请求，获取响应进行处理；
    brpc::Controller* cntl = new brpc::Controller;
    example::EchoRequest req;
    req.set_message("你好呀，RPC");

    example::EchoResponse* rsp = new example::EchoResponse;
    // /*这个是rpc同步调用所以最后一个参数传nullptr就可以，会阻塞等待响应，
    // rpc异步调用最后一个参数传Closure对象，并给Closure对象设置客户端收到响应后的回调函数；*/
    // stub.Echo(cntl, &req, rsp, nullptr);  //rpc同步调用
    // if(cntl->Failed() == true)
    // {
    //     std::cout << "Rpc 调用失败！" << cntl->ErrorText() << std::endl;
    //     delete cntl;
    //     delete rsp;
    //     return -1;
    // }
    // std::cout << "收到的响应：" << rsp->message() << std::endl;
    // //这里是有一定资源泄露的，如果Rpc调用失败，cntl和rsp就都不会delete，最后的方法是使用智能指针管理
    // delete cntl;
    // delete rsp;

    google::protobuf::Closure* closure = google::protobuf::NewCallback(callback, cntl, rsp);
    stub.Echo(cntl, &req, rsp, closure);    //rpc异步调用
    std::cout << "Rpc异步调用结束!" << std::endl;
    std::this_thread::sleep_for(std::chrono::seconds(3));
    return 0;
}